package ru.ipccenter.jshell.frontend.compiler;

import java.io.*;
import java.util.Map;


public class ShellClassLoader extends ClassLoader {
  
  private String classPath;
  private Map<String, MemoryByteCode> byteCode;
  
  public ShellClassLoader(ClassLoader parent) {
    
    super(parent);
  }
 
  public ShellClassLoader(Map<String, MemoryByteCode> byteCode, ClassLoader parent) {

    super(parent);
    this.byteCode = byteCode;
  }
  
  public ShellClassLoader(String classPath, ClassLoader parent) {
    
    super(parent);
    this.classPath = classPath;
  }
  
  
  public String getClassPath() {
    
    return classPath;
  }

  public void setClassPath(String classPath) {
    
    this.classPath = classPath;
  }

  public Map<String, MemoryByteCode> getByteCode() {
    
    return byteCode;
  }

  public void setByteCode(Map<String, MemoryByteCode> byteCode) {
    
    this.byteCode = byteCode;
  }

  @Override
  protected Class<?> findClass(String className) throws ClassNotFoundException {
    
    try {
      if (null != classPath) {
        
        byte[] bytes = fetchClassFromFS(classPath + "/" + className + ".class");
        return defineClass(className, bytes, 0, bytes.length);
      } else if (null != byteCode && byteCode.containsKey(className)) {
        
        byte[] bytes = byteCode.get(className).toByteArray();
        return defineClass(className, bytes, 0, bytes.length);
      } else {
        
        return super.findClass(className);
      }
    } catch (FileNotFoundException e) {
      return super.findClass(className);
    } catch (IOException e) {
      return super.findClass(className);
    }
  }

  private byte[] fetchClassFromFS(String path) throws FileNotFoundException, IOException {
    
    InputStream is = new FileInputStream(new File(path));
    
    long length = new File(path).length();
  
    if (length > Integer.MAX_VALUE) {

    }
  
    byte[] bytes = new byte[(int)length];
  
    int offset = 0;
    int numRead = 0;
    while (offset < bytes.length
        && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
      offset += numRead;
    }
  
    if (offset < bytes.length) {
      throw new IOException("Could not completely read file "+path);
    }
  
    is.close();
    return bytes;
  }
}
